"""
数据处理器
Data Processor

处理IoT设备数据的统一入口和流水线
Unified entry point and pipeline for processing IoT device data
"""

import logging
import asyncio
from typing import Dict, Any, Optional, List, Callable
from datetime import datetime
from enum import Enum

from .device_manager import device_manager
from ..interfaces.device_interface import DeviceInterface
from ..utils.resilience import safe_execute, resilience_manager, retry, circuit_breaker

logger = logging.getLogger(__name__)


class ProcessingStatus(Enum):
    """
    数据处理状态枚举
    Data processing status enumeration
    """
    SUCCESS = "success"      # 成功 / Success
    FAILED = "failed"        # 失败 / Failed  
    PARTIAL = "partial"      # 部分成功 / Partial success
    PENDING = "pending"      # 待处理 / Pending
    TIMEOUT = "timeout"      # 超时 / Timeout


class DataProcessor:
    """
    数据处理器
    Data Processor
    
    负责处理来自IoT设备的数据，提供统一的数据处理接口
    Responsible for processing data from IoT devices, providing unified data processing interface
    """
    
    def __init__(self):
        """初始化数据处理器 / Initialize data processor"""
        self.logger = logging.getLogger(f"{self.__class__.__name__}")
        self.processing_stats = {
            'total_processed': 0,
            'successful': 0,
            'failed': 0,
            'last_processed': None
        }
        
        # 数据预处理器列表 / Data preprocessor list
        self.preprocessors: List[Callable] = []
        
        # 数据后处理器列表 / Data postprocessor list
        self.postprocessors: List[Callable] = []
        
        # 处理超时时间（秒）/ Processing timeout (seconds)
        self.processing_timeout = 30
    
    def add_preprocessor(self, processor: Callable):
        """
        添加数据预处理器
        Add data preprocessor
        
        Args:
            processor (Callable): 预处理函数 / Preprocessor function
        """
        self.preprocessors.append(processor)
        self.logger.info(f"添加预处理器 / Added preprocessor: {processor.__name__}")
    
    def add_postprocessor(self, processor: Callable):
        """
        添加数据后处理器
        Add data postprocessor
        
        Args:
            processor (Callable): 后处理函数 / Postprocessor function
        """
        self.postprocessors.append(processor)
        self.logger.info(f"添加后处理器 / Added postprocessor: {processor.__name__}")
    
    async def process_device_data(self, device_id: str, raw_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        处理设备数据
        Process device data
        
        Args:
            device_id (str): 设备ID / Device ID
            raw_data (Dict[str, Any]): 原始数据 / Raw data
            
        Returns:
            Dict[str, Any]: 处理结果 / Processing result
        """
        start_time = datetime.now()
        processing_id = f"{device_id}_{int(start_time.timestamp())}"
        
        try:
            # 参数验证 / Parameter validation
            if not device_id or not isinstance(device_id, str):
                return self._create_error_response(processing_id, "无效的设备ID / Invalid device ID")
            
            if not isinstance(raw_data, dict) or not raw_data:
                return self._create_error_response(processing_id, "无效的数据格式 / Invalid data format")
            
            self.logger.info(f"开始处理设备数据 / Starting to process device data: {device_id}")
            
            # 更新统计信息 / Update statistics
            self.processing_stats['total_processed'] += 1
            
            # 获取或注册设备 / Get or register device
            device = await self._get_or_create_device(device_id, raw_data)
            if not device:
                self.processing_stats['failed'] += 1
                return self._create_error_response(processing_id, "设备创建失败 / Device creation failed")
            
            # 数据预处理 / Data preprocessing
            try:
                preprocessed_data = await self._run_preprocessors(raw_data)
            except Exception as preprocess_error:
                self.logger.error(f"数据预处理失败 / Data preprocessing failed: {str(preprocess_error)}")
                preprocessed_data = raw_data  # 使用原始数据 / Use raw data as fallback
            
            # 设备数据验证 / Device data validation
            try:
                is_valid = await device.validate_data(preprocessed_data)
                if not is_valid:
                    self.logger.warning(f"数据验证失败，但继续处理 / Data validation failed, but continuing processing: {device_id}")
                    # 不立即返回错误，尝试继续处理 / Don't return error immediately, try to continue processing
            except Exception as validation_error:
                self.logger.error(f"数据验证异常 / Data validation exception: {str(validation_error)}")
                # 继续处理 / Continue processing
            
            # 设备数据处理 / Device data processing
            try:
                processing_result = await safe_execute(
                    device.process_data,
                    preprocessed_data,
                    max_attempts=3,
                    circuit_breaker_name=f"device_processing_{device_id}"
                )
            except asyncio.TimeoutError:
                self.processing_stats['failed'] += 1
                raise
            except Exception as process_error:
                self.logger.error(f"设备数据处理失败 / Device data processing failed: {str(process_error)}")
                self.processing_stats['failed'] += 1
                raise
            
            # 数据后处理 / Data postprocessing
            try:
                final_result = await self._run_postprocessors(processing_result, device)
            except Exception as postprocess_error:
                self.logger.error(f"数据后处理失败 / Data postprocessing failed: {str(postprocess_error)}")
                final_result = processing_result  # 使用处理结果 / Use processing result as fallback
            
            # 安全更新设备状态 / Safely update device status
            try:
                await device_manager.update_device_status(device_id, True)
            except Exception as status_error:
                self.logger.warning(f"更新设备状态失败 / Failed to update device status: {str(status_error)}")
            
            # 更新统计信息 / Update statistics
            self.processing_stats['successful'] += 1
            self.processing_stats['last_processed'] = datetime.now()
            
            processing_time = (datetime.now() - start_time).total_seconds()
            self.logger.info(f"设备数据处理完成 / Device data processing completed: {device_id} (耗时 / Duration: {processing_time:.2f}s)")
            
            return {
                'processing_id': processing_id,
                'status': ProcessingStatus.SUCCESS.value,
                'device_id': device_id,
                'processing_time': processing_time,
                'result': final_result,
                'timestamp': datetime.now().isoformat()
            }
            
        except asyncio.TimeoutError:
            self.logger.error(f"设备数据处理超时 / Device data processing timeout: {device_id}")
            self.processing_stats['failed'] += 1
            return self._create_error_response(processing_id, "处理超时 / Processing timeout", ProcessingStatus.TIMEOUT)
            
        except Exception as e:
            self.logger.error(f"设备数据处理异常 / Device data processing error: {device_id}, {str(e)}")
            self.processing_stats['failed'] += 1
            return self._create_error_response(processing_id, f"处理异常 / Processing error: {str(e)}")
    
    async def batch_process_data(self, data_batch: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        批量处理设备数据
        Batch process device data
        
        Args:
            data_batch (List[Dict[str, Any]]): 数据批次 / Data batch
            
        Returns:
            Dict[str, Any]: 批量处理结果 / Batch processing result
        """
        try:
            self.logger.info(f"开始批量处理设备数据 / Starting batch processing device data: {len(data_batch)} items")
            
            # 限制并发数量以避免资源耗尽 / Limit concurrency to avoid resource exhaustion
            max_concurrent = min(50, len(data_batch))  # 最多50个并发任务
            semaphore = asyncio.Semaphore(max_concurrent)
            
            async def process_single_item(data_item):
                async with semaphore:
                    device_id = data_item.get('device_id') or data_item.get('imei') or data_item.get('deviceId')
                    if not device_id:
                        return {
                            'status': ProcessingStatus.FAILED.value,
                            'error': '缺少设备ID / Missing device ID',
                            'data_item': data_item
                        }
                    return await self.process_device_data(device_id, data_item)
            
            # 创建任务 / Create tasks
            tasks = [process_single_item(data_item) for data_item in data_batch]
            
            if not tasks:
                return {
                    'status': ProcessingStatus.FAILED.value,
                    'message': '没有有效的设备数据 / No valid device data',
                    'results': []
                }
            
            # 等待所有任务完成 / Wait for all tasks to complete
            results = await asyncio.gather(*tasks, return_exceptions=True)
            
            # 统计处理结果 / Count processing results
            successful = 0
            failed = 0
            processed_results = []
            
            for i, result in enumerate(results):
                if isinstance(result, Exception):
                    failed += 1
                    processed_results.append({
                        'index': i,
                        'status': ProcessingStatus.FAILED.value,
                        'error': str(result)
                    })
                else:
                    if result.get('status') == ProcessingStatus.SUCCESS.value:
                        successful += 1
                    else:
                        failed += 1
                    processed_results.append(result)
            
            # 确定批量处理状态 / Determine batch processing status
            if successful == len(results):
                batch_status = ProcessingStatus.SUCCESS
            elif successful > 0:
                batch_status = ProcessingStatus.PARTIAL
            else:
                batch_status = ProcessingStatus.FAILED
            
            return {
                'status': batch_status.value,
                'total': len(data_batch),
                'successful': successful,
                'failed': failed,
                'results': processed_results,
                'timestamp': datetime.now().isoformat()
            }
            
        except Exception as e:
            self.logger.error(f"批量处理设备数据异常 / Batch processing device data error: {str(e)}")
            return {
                'status': ProcessingStatus.FAILED.value,
                'error': str(e),
                'results': []
            }
    
    async def _get_or_create_device(self, device_id: str, raw_data: Dict[str, Any]) -> Optional[DeviceInterface]:
        """
        获取或创建设备实例
        Get or create device instance
        
        Args:
            device_id (str): 设备ID / Device ID
            raw_data (Dict[str, Any]): 原始数据 / Raw data
            
        Returns:
            Optional[DeviceInterface]: 设备实例 / Device instance
        """
        try:
            # 参数验证 / Parameter validation
            if not device_id or not isinstance(device_id, str):
                self.logger.error("无效的设备ID / Invalid device ID")
                return None
                
            device_id = device_id.strip()
            if not device_id:
                self.logger.error("设备ID不能为空 / Device ID cannot be empty")
                return None
            
            # 尝试获取现有设备 / Try to get existing device
            try:
                device = device_manager.get_device(device_id)
                if device:
                    return device
            except Exception as get_error:
                self.logger.warning(f"获取现有设备失败 / Failed to get existing device: {str(get_error)}")
            
            # 根据数据推断设备类型 / Infer device type from data
            device_type = self._infer_device_type(raw_data)
            if not device_type:
                self.logger.error(f"无法推断设备类型 / Cannot infer device type: {device_id}")
                return None
            
            # 注册新设备 / Register new device
            try:
                device = await device_manager.register_device(device_id, device_type)
                self.logger.info(f"成功创建新设备 / Successfully created new device: {device_id} ({device_type})")
                return device
            except Exception as register_error:
                self.logger.error(f"注册新设备失败 / Failed to register new device: {device_id}, {str(register_error)}")
                return None
            
        except Exception as e:
            self.logger.error(f"获取或创建设备失败 / Failed to get or create device: {device_id}, {str(e)}")
            return None
    
    def _infer_device_type(self, raw_data: Dict[str, Any]) -> Optional[str]:
        """
        根据数据推断设备类型
        Infer device type from data
        
        Args:
            raw_data (Dict[str, Any]): 原始数据 / Raw data
            
        Returns:
            Optional[str]: 设备类型 / Device type
        """
        try:
            if not isinstance(raw_data, dict) or not raw_data:
                return None
            
            # 更严格的L16设备类型推断 / More strict L16 device type inference
            if 'action' in raw_data:
                action = raw_data.get('action')
                valid_l16_actions = ['location', 'health', 'battery', 'warning', 'audio']
                if action in valid_l16_actions:
                    return 'L16'
            
            # 检查设备ID格式推断 / Check device ID format for inference
            device_id = raw_data.get('device_id') or raw_data.get('imei') or raw_data.get('deviceId')
            if device_id:
                device_id_str = str(device_id).upper()
                # S8设备ID可能包含S8标识 / S8 device ID may contain S8 identifier
                if 'S8' in device_id_str:
                    return 'S8'
                # L16设备ID可能是15位数字 / L16 device ID may be 15-digit number
                elif len(device_id_str) == 15 and device_id_str.isdigit():
                    return 'L16'
            
            # 根据数据字段推断 / Infer based on data fields
            l16_indicators = ['heart_rate', 'blood_oxygen', 'body_temperature', 'pedometer']
            s8_indicators = ['accelerometer', 'gyroscope', 'alert_type', 'firmware_version', 'steps']
            
            l16_score = sum(1 for field in l16_indicators if field in raw_data)
            s8_score = sum(1 for field in s8_indicators if field in raw_data)
            
            if l16_score > s8_score and l16_score > 0:
                return 'L16'
            elif s8_score > 0:
                return 'S8'
            
            # 默认返回L16（向后兼容）/ Default to L16 (backward compatibility)
            return 'L16'
            
        except Exception as e:
            self.logger.error(f"推断设备类型失败 / Failed to infer device type: {str(e)}")
            return 'L16'  # 失败时默认为L16 / Default to L16 on failure
    
    async def _run_preprocessors(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """
        运行数据预处理器
        Run data preprocessors
        
        Args:
            data (Dict[str, Any]): 原始数据 / Raw data
            
        Returns:
            Dict[str, Any]: 预处理后的数据 / Preprocessed data
        """
        processed_data = data.copy()
        
        for preprocessor in self.preprocessors:
            try:
                if asyncio.iscoroutinefunction(preprocessor):
                    processed_data = await preprocessor(processed_data)
                else:
                    processed_data = preprocessor(processed_data)
            except Exception as e:
                self.logger.error(f"预处理器异常 / Preprocessor error: {preprocessor.__name__}, {str(e)}")
        
        return processed_data
    
    async def _run_postprocessors(self, result: Any, device: DeviceInterface) -> Any:
        """
        运行数据后处理器
        Run data postprocessors
        
        Args:
            result (Any): 处理结果 / Processing result
            device (DeviceInterface): 设备实例 / Device instance
            
        Returns:
            Any: 后处理后的结果 / Postprocessed result
        """
        processed_result = result
        
        for postprocessor in self.postprocessors:
            try:
                if asyncio.iscoroutinefunction(postprocessor):
                    processed_result = await postprocessor(processed_result, device)
                else:
                    processed_result = postprocessor(processed_result, device)
            except Exception as e:
                self.logger.error(f"后处理器异常 / Postprocessor error: {postprocessor.__name__}, {str(e)}")
        
        return processed_result
    
    def _create_error_response(self, processing_id: str, error_message: str, 
                             status: ProcessingStatus = ProcessingStatus.FAILED) -> Dict[str, Any]:
        """
        创建错误响应
        Create error response
        
        Args:
            processing_id (str): 处理ID / Processing ID
            error_message (str): 错误消息 / Error message
            status (ProcessingStatus): 处理状态 / Processing status
            
        Returns:
            Dict[str, Any]: 错误响应 / Error response
        """
        return {
            'processing_id': processing_id,
            'status': status.value,
            'error': error_message,
            'timestamp': datetime.now().isoformat()
        }
    
    def get_processing_statistics(self) -> Dict[str, Any]:
        """
        获取处理统计信息
        Get processing statistics
        
        Returns:
            Dict[str, Any]: 统计信息 / Statistics information
        """
        stats = self.processing_stats.copy()
        
        # 计算成功率 / Calculate success rate
        if stats['total_processed'] > 0:
            stats['success_rate'] = round(stats['successful'] / stats['total_processed'] * 100, 2)
        else:
            stats['success_rate'] = 0
        
        # 格式化时间 / Format time
        if stats['last_processed']:
            stats['last_processed'] = stats['last_processed'].isoformat()
        
        return stats
    
    async def clear_statistics(self):
        """清空统计信息 / Clear statistics"""
        self.processing_stats = {
            'total_processed': 0,
            'successful': 0,
            'failed': 0,
            'last_processed': None
        }
        self.logger.info("处理统计信息已清空 / Processing statistics cleared")


# 全局数据处理器实例 / Global data processor instance
data_processor = DataProcessor()